package me.stone.stanimeclient.core.common.utils

import android.view.View
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.LifecycleOwner
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty


fun <V: View> View.bindView(id: Int)
    : ReadOnlyProperty<View, V> = required(id, viewFinder)


private val View.viewFinder: View.(Int) -> View?
    get() = { findViewById(it) }

private fun viewNotFound(id: Int, desc: KProperty<*>): Nothing =
    throw IllegalStateException("View id $id for '${desc.name}' not found")

@Suppress("UNCHECKED_CAST")
private fun <T, V: View> required(
    id: Int,
    finder: T.(Int) -> View?,
    onInitializedListener: ((V) -> Unit)? = null
) = Lazy { t: T, desc ->
    t.finder(id) as V? ?: viewNotFound(id, desc)
}.apply { this.onInitializedListener = onInitializedListener }


private class Lazy<T, V>(
    private val initializer: (T, KProperty<*>) -> V
): ReadOnlyProperty<T, V>, LifecycleObserver {

    var onInitializedListener: ((V) -> Unit)? = null

    private object EMPTY

    private var value: Any? = EMPTY

    private var attachedToLifecycleOwner = false

    override fun getValue(thisRef: T, property: KProperty<*>): V {
        checkAddToLifecycleOwner(thisRef)
        if (value == EMPTY) {
            value = initializer.invoke(thisRef, property)
        }

        @Suppress("UNCHECKED_CAST")
        val view = value as V

        onInitializedListener?.invoke(view)
        return view
    }

    private fun checkAddToLifecycleOwner(thisRef: T) {
        if (!attachedToLifecycleOwner && thisRef is LifecycleOwner) {
            thisRef.lifecycle.addObserver(this)
            attachedToLifecycleOwner = false
        }
    }

}